package com.yu.transport.handler;

import com.yu.factory.SingletonFactory;
import com.yu.transfer.RpcMessage;
import com.yu.transfer.RpcResponse;
import com.yu.transport.client.NettyClient;
import com.yu.transport.client.UnprocessedRequests;
import com.yu.transport.constants.NettyConstants;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * @PackageName: com.yu.transport.handler
 * @Description:
 * @Version: v1.0.0
 * @Author: yuweilin
 * @Date: 20:30
 * <p>
 * Modification History:
 * Date         Author          Version            Description
 * ------------------------------------------------------------
 * 2021/2/5      yuweilin         v1.0.0               新建
 */
@Slf4j
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    private final UnprocessedRequests unprocessedRequests;
    private final NettyClient nettyClient;

    public NettyClientHandler() {
        unprocessedRequests = SingletonFactory.getInstance(UnprocessedRequests.class);
        nettyClient = SingletonFactory.getInstance(NettyClient.class);
    }

    /**
     * 读取经过解码的内容
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            log.info("客户端接收消息：{}",msg);
            if (msg instanceof RpcMessage){
                RpcMessage message = (RpcMessage) msg;
                RpcResponse<Object> rpcResponse = (RpcResponse<Object>) message.getData();
                unprocessedRequests.complete(rpcResponse);
            }
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent){
            IdleState state = ((IdleStateEvent) evt).state();
            if (state==IdleState.WRITER_IDLE){
                log.info("{}通道写超时",ctx.channel().remoteAddress());
                Channel channel = nettyClient.getChannel((InetSocketAddress) ctx.channel().remoteAddress());
                RpcMessage message = new RpcMessage();
                message.setMessageType(NettyConstants.HEARTBEAT_TYPE);
                message.setData(NettyConstants.PING);
                channel.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        }else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("客户端捕捉异常：", cause);
        cause.printStackTrace();
        ctx.close();
    }
}
